/*-------------------------------------------------------------------------
   Copyright (C) 2011 One Laptop per Child

   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2, or (at your option) any
   later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

   In other words, you are welcome to use, share and improve this program.
   You are forbidden to forbid anyone else to use, share and improve
   what you give them.   Help stamp out software-hoarding!

   As a special exception, you may use this file as part of a free software
   library for the XO of the One Laptop per Child project without restriction.
   Specifically, if other files instantiate
   templates or use macros or inline functions from this file, or you compile
   this file and link it with other files to produce an executable, this
   file does not by itself cause the resulting executable to be covered by
   the GNU General Public License.  This exception does not however
   invalidate any other reasons why the executable file might be covered by
   the GNU General Public License.
-------------------------------------------------------------------------*/

#undef THW_SHOW_STATES

#include <stdio.h>
#include "cc_compat.h"
#include "every.h"
#include "ac.h"
#include "event.h"
#include "timer.h"
#include "power.h"


#define STACK_CHECK (0xabcd)
#define STACK_CHECK_LOC ((unsigned int __idata *)0xe0)

void stack_check_init(void)
{
	// place cookie near top of stack
	*STACK_CHECK_LOC = STACK_CHECK;
}

void stack_check(void)
{
	static bool reported;
	if (!reported && *STACK_CHECK_LOC != STACK_CHECK)
	{
		puts("Stack overflow?\n");
		reported = 1;
	}
}

#define THW_INACTIVE 	0
#define THW_INIT	1
#define THW_SET_TIMER 	2
#define THW_WATCH_TIMER	3
#define THW_DO_WAKEUP	4

static unsigned char xdata thw_state;
static unsigned char xdata thw_enabled;
static unsigned char xdata thw_autorepeat;
static unsigned long xdata thw_timer;
static unsigned long xdata thw_timer_value;

void timed_host_wakeups_process(void)
{
#ifdef THW_SHOW_STATES
	static int last_thw_state;
	if (last_thw_state != thw_state)
	{
		printf("thw_state: %d\n", (uint)thw_state);
		last_thw_state = thw_state;
	}
#endif
	switch (thw_state)
	{
		case THW_INACTIVE:
			thw_enabled = 0;
			break;

		case THW_INIT:
			thw_state = THW_SET_TIMER;
			thw_enabled = 1;
			break;

		case THW_SET_TIMER:
			print_tstamp();
			printf("thw %ld\n",thw_timer_value);
			thw_timer=get_ms_timer_ext();
			thw_state = THW_WATCH_TIMER;
			break;

		case THW_WATCH_TIMER:
			if (check_timer_ext(thw_timer,thw_timer_value))
			{
				thw_state = THW_DO_WAKEUP;
			}
			break;

		case THW_DO_WAKEUP:
			// Default is to keep going
			thw_state = THW_INIT;

			print_tstamp();
			printf("thw fire\n");
			// Generate the wakeup
			event_send_event(EVENT_TIMED_HOST_WAKE);

			// If autorepeat isn't set then stop.
			// (else repeate with the same timer value)
			if (!thw_autorepeat)
			{
				thw_state = THW_INACTIVE;
			}
			break;
	}
}

void timed_host_wakeup_cmd_enable(unsigned char val)
{
	thw_enabled = val;
	if (val)
	{
		printf("thw enabled\n");
		thw_state = THW_INIT;
	}
	else
	{
		thw_state = THW_INACTIVE;
	}

}

void timed_host_wakeup_cmd_autorepeat(unsigned char val)
{
	printf("thw auto %d\n", (uint)val);
	thw_autorepeat = val;
}

void timed_host_wakeup_cmd_value(unsigned long val)
{
	printf("thw time %ld\n", val);
	thw_timer_value = val;
}

unsigned char timed_host_wakeup_active(void)
{
	return thw_state != THW_INACTIVE;
}


void every_process(void)
{
	// Compute the Vin average
	DO_VIN_AVG;

	timed_host_wakeups_process();

	check_soc_sleep();

}

